//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <bsp.h>
#include <timer.h>
#include "uart.h"

EXTERN_C bool_t CDECL BspSetupComPort(
    ComPort comPort, const ComPortSettings *pSettings)
{

    if (!COMPORT_AVAILABLE(comPort)) return FALSE;

    ComPortSettings defaultSettings = {
        115200,
        ComPortByteSize_Default,
        ComPortParity_Default,
        ComPortStopBits_Default
    };

    if (NULL == pSettings) pSettings = &defaultSettings;

    // Make the line parameter
    uint_t uLineParams = 0;

    switch (pSettings->byteSize) {
    case ComPortByteSize_5:     uLineParams |= ULCON_WL_5;    break;
    case ComPortByteSize_6:     uLineParams |= ULCON_WL_6;    break;
    case ComPortByteSize_7:     uLineParams |= ULCON_WL_7;    break;
    case ComPortByteSize_8:     uLineParams |= ULCON_WL_8;    break;
    default: return FALSE;
    }

    switch (pSettings->stopBits) {
    case ComPortStopBits_One:   uLineParams |= ULCON_SB_1;    break;
    case ComPortStopBits_One5:  uLineParams |= ULCON_SB_1_5;  break;
    case ComPortStopBits_Two:   uLineParams |= ULCON_SB_2;    break;
    default: return FALSE;
    }

    switch (pSettings->parity) {
    case ComPortParity_No:      uLineParams |= ULCON_NP;      break;
    case ComPortParity_Odd:     uLineParams |= ULCON_OP;      break;
    case ComPortParity_Even:    uLineParams |= ULCON_EP;      break;
    case ComPortParity_Mark:    uLineParams |= ULCON_HP;      break;
    case ComPortParity_Space:   uLineParams |= ULCON_LP;      break;
    default: return FALSE;
    }


    // Make the baudrate divisor
    uint_t uBaudDiv = ((int)(PCLK / 16 /pSettings->uBaudRate) - 1);

    const ioport_t iobase = COMPORT_IOBASE(comPort);

    Outl(_UART_UFCON(iobase), 0);
    Outl(_UART_UMCON(iobase), 0);

    // Set line parameters
    Outl(_UART_ULCON(iobase), uLineParams);

    Outl(_UART_UCON(iobase), 0x245);

    // Set baut rate
    Outl(_UART_UBRDIV(iobase), uBaudDiv);

    return TRUE;
}

EXTERN_C bool_t CDECL BspWriteComPort(ComPort comPort, uint8_t u8Data)
{
#if !defined(_RELEASE) || defined(_PRERELEASE) || defined(_TEST_TYPE)
    if (!COMPORT_AVAILABLE(comPort)) return FALSE;

    const ioport_t iobase = COMPORT_IOBASE(comPort);

    while (0 == (Inl(_UART_UTRSTAT(iobase)) & 0x2));
    Outb(_UART_UTXH(iobase), u8Data);
#endif
    return TRUE;
}

EXTERN_C void NotifyByIsr(int eType, int nCode, void *pParam);
EXTERN_C bool_t CDECL BspReadComPort(ComPort comPort, uint8_t *pu8Data)
{
    if (NULL == pu8Data) return FALSE;

    if (!COMPORT_AVAILABLE(comPort)) return FALSE;

    const ioport_t iobase = COMPORT_IOBASE(comPort);

    uint_t utrstat;

    while (TRUE) {
        utrstat = Inb(_UART_UTRSTAT(iobase));
        if (utrstat & 0x1) break;
        // Has errors ?
        if (Inb(_UART_UERSTAT(iobase)) & 0x7) return FALSE;
    }

    *pu8Data = Inl(_UART_URXH(iobase));

    return TRUE;
}

EXTERN_C bool_t CDECL BspTryReadComPort(
    ComPort comPort, uint8_t *pu8Data, uint_t uTimes)
{
    if (NULL == pu8Data) return FALSE;

    if (!COMPORT_AVAILABLE(comPort)) return FALSE;

    const ioport_t iobase = COMPORT_IOBASE(comPort);

    uint_t utrstat;

    while (TRUE) {
        utrstat = Inb(_UART_UTRSTAT(iobase));
        if (utrstat & 0x1) break;
        // Has errors ?
        if (Inb(_UART_UERSTAT(iobase)) & 0x7) return FALSE;

        return FALSE;//timeout
    }

    *pu8Data = Inl(_UART_URXH(iobase));

    return TRUE;
}
